// -----------------------------
// Author: 		Dhaenens Gert 
// Creation: 	8/5/2013 9:14:14 PM				
// -----------------------------

#ifndef _LuaTableInl_h
#define _LuaTableInl_h

#include "LuaObject.h"
#include "LuaRef.h"
#include "LuaFunction.h"

namespace ObjectLua
{


	/*
	//	Add a Function with Closure Object
	//	To the table
	//	@ name : name of the key
	//	@ value : value of the key
	//	@ object : object to be assigned
	*/
	template<typename T>
	void LuaTable::addClosure(const char* name, int (*value)(lua_State*), T* object)
	{
		LUA_ASSERT(name);
		LUA_ASSERT(value);
		LuaStackGuard stackGuard(m_lpLua);
		m_Ref.push();

		LuaStack* lpStack = m_lpLua->getStack();
		lpStack->pushString(name);
		size_t objectSize = sizeof(T);
		void* lpMemBlock = lpStack->requestUserData(objectSize);
		memcpy_s(lpMemBlock,objectSize,object,objectSize);
		lpStack->pushClosure(value,1);
		lpStack->setTable(-3);
	}
	/*
	//	Add a function to the table
	//	with 0 arguments
	//	@ name : name of the key
	//	@ value : value of the key
	*/
	template<typename R>
	void LuaTable::addFunction(const char* name, R (*value)())
	{
		LUA_ASSERT(name);
		LUA_ASSERT(value);
		LuaStackGuard stackGuard(m_lpLua);
		m_Ref.push();
		Internal::LuaFunction_0<R>::bind(m_lpLua,this,name,value);
	}

	/*
	//	Add a function to the table
	//	with 1 argument
	//	@ name : name of the key
	//	@ value : value of the key
	*/
	template<typename R, typename P0>
	void LuaTable::addFunction(const char* name, R (*value)(P0))
	{
		LUA_ASSERT(name);
		LUA_ASSERT(value);
		LuaStackGuard stackGuard(m_lpLua);
		m_Ref.push();
		Internal::LuaFunction_1<R,P0>::bind(m_lpLua,this,name,value);
	}

	/*
	//	Add a function to the table
	//	with 2 arguments
	//	@ name : name of the key
	//	@ value : value of the key
	*/
	template<typename R, typename P0, typename P1>
	void LuaTable::addFunction(const char* name, R(*value)(P0,P1))
	{
		LUA_ASSERT(name);
		LUA_ASSERT(value);
		LuaStackGuard stackGuard(m_lpLua);
		m_Ref.push();
		Internal::LuaFunction_2<R,P0,P1>::bind(m_lpLua,this,name,value);
	}

	/*
	//	Add a function to the table
	//	with 3 arguments
	//	@ name : name of the key
	//	@ value : value of the key
	*/
	template<typename R, typename P0, typename P1, typename P2>
	void LuaTable::addFunction(const char* name, R (*value)(P0,P1,P2))
	{
		LUA_ASSERT(name);
		LUA_ASSERT(value);
		LuaStackGuard stackGuard(m_lpLua);
		m_Ref.push();
		Internal::LuaFunction_3<R,P0,P1,P2>::bind(m_lpLua,this,name,value);
	}

	/*
	//	Add a function to the table
	//	with 4 arguments
	//	@ name : name of the key
	//	@ value : value of the key
	*/
	template<typename R, typename P0, typename P1, typename P2, typename P3>
	void LuaTable::addFunction(const char* name, R (*value)(P0,P1,P2,P3))
	{
		LUA_ASSERT(name);
		LUA_ASSERT(value);
		LuaStackGuard stackGuard(m_lpLua);
		m_Ref.push();
		Internal::LuaFunction_4<R,P0,P1,P2,P3>::bind(m_lpLua,this,name,value);
	}

	/*
	//	Add a function to the table
	//	with 5 arguments
	//	@ name : name of the key
	//	@ value : value of the key
	*/
	template<typename R, typename P0, typename P1, typename P2, typename P3, typename P4>
	void LuaTable::addFunction(const char* name, R (*value)(P0,P1,P2,P3,P4))
	{
		LUA_ASSERT(name);
		LUA_ASSERT(value);
		LuaStackGuard stackGuard(m_lpLua);
		m_Ref.push();
		Internal::LuaFunction_5<R,P0,P1,P2,P3,P4>::bind(m_lpLua,this,name,value);
	}

	/*
	//	Add a function to the table
	//	with 6 arguments
	//	@ name : name of the key
	//	@ value : value of the key
	*/
	template<typename R, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5>
	void LuaTable::addFunction(const char* name, R (*value)(P0,P1,P2,P3,P4,P5))
	{
		LUA_ASSERT(name);
		LUA_ASSERT(value);
		LuaStackGuard stackGuard(m_lpLua);
		m_Ref.push();
		Internal::LuaFunction_6<R,P0,P1,P2,P3,P4,P5>::bind(m_lpLua,this,name,value);
	}

	/*
	//	Add a function to the table
	//	with 7 arguments
	//	@ name : name of the key
	//	@ value : value of the key
	*/
	template<typename R, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
	void LuaTable::addFunction(const char* name, R (*value)(P0,P1,P2,P3,P4,P5,P6))
	{
		LUA_ASSERT(name);
		LUA_ASSERT(value);
		LuaStackGuard stackGuard(m_lpLua);
		m_Ref.push();
		Internal::LuaFunction_7<R,P0,P1,P2,P3,P4,P5,P6>::bind(m_lpLua,this,name,value);
	}

	/*
	//	Add a Class to the Table
	//	@ name : name of the key
	*/
	template<typename Class>
	LuaClass<Class> LuaTable::addClass(const char* name)
	{
		LUA_ASSERT(name);
		LuaStackGuard stackGuard(m_lpLua);
		m_Ref.push();
		return LuaClass<Class>::bind(m_lpLua,name);
	}

	template<typename Class>
	void LuaTable::addObject(const char* name, const char* metaName, Class* lpObject)
	{
		
		LUA_ASSERT(name);
		LUA_ASSERT(lpObject);

		LuaStackGuard stackGuard(m_lpLua);

		// Request the User Data
		LuaDataType<Class*>::push(m_lpLua, lpObject);
		// Push it again for next use

		// Save the User Data
		m_lpLua->getStack()->setGlobal(name);
	}


}

#endif